package com.yinxing.framework.utils;

import com.yinxing.framework.exception.YinXingException;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.*;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.ContentBody;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.DefaultConnectionKeepAliveStrategy;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

import java.io.Closeable;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

@Slf4j
public class HttpUtils {

    private static CloseableHttpClient httpClient;

    static {
        PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();
        connectionManager.setMaxTotal(500);
        connectionManager.setDefaultMaxPerRoute(50);

        httpClient = HttpClients.custom()
                .setConnectionManager(connectionManager)
                .setKeepAliveStrategy(DefaultConnectionKeepAliveStrategy.INSTANCE)
                .setDefaultRequestConfig(RequestConfig.custom().build())
                .build();
    }

    /**
     * application-json方式提交
     * @param url http路径 例如：http://ip:port/api/adduser
     * @param json json字符串 {"key1":"value2", "key2":"value2"}
     * @return 响应内容字符串
     */
    public static String postJson(String url, String json) {
        HttpPost httpPost = new HttpPost(url);
        httpPost.setEntity(new StringEntity(json, ContentType.APPLICATION_JSON));
        try(CloseableHttpResponse response = httpClient.execute(httpPost)) {
            return EntityUtils.toString( response.getEntity());
        } catch (IOException e) {
            log.error("http.postJson", e);
            throw new YinXingException("http.postJson出现异常");
        }
    }

    /**
     * application/x-www-form-urlencoded 方式提交
     * @param url http路径
     * @param kvMap key与value组成的map
     * @return 响应内容字符串
     */
    public String postForm(String url, Map<String, String> kvMap) {
        HttpPost httpPost = new HttpPost(url);
        List<NameValuePair> nvps = new ArrayList<>();
        kvMap.forEach((key, value) -> nvps.add(new BasicNameValuePair(key, value)));
        CloseableHttpResponse response = null;
        try {
            httpPost.setEntity(new UrlEncodedFormEntity(nvps));
            response = httpClient.execute(httpPost);
            return EntityUtils.toString(response.getEntity());
        } catch (Exception e) {
            log.error("http.postForm", e);
            throw new YinXingException("http.postForm出现异常");
        } finally {
            closeResource(response);
        }
    }

    /**
     * form-data方式提交文件
     * @param url http路径
     * @param valueMap 字符串key-valye
     * @param bodyMap 文件key-ContentBody
     * @return 响应内容字符串
     */
    public static String postFile(String url, Map<String, String> valueMap, Map<String, ContentBody> bodyMap) {
        HttpPost httpPost = new HttpPost(url);

        MultipartEntityBuilder build = MultipartEntityBuilder.create();
        bodyMap.entrySet().forEach(entry -> build.addPart(entry.getKey(), entry.getValue()));
        valueMap.entrySet().forEach(entry -> build.addPart(entry.getKey(),
                new StringBody(entry.getKey(), ContentType.create("text/plain", Consts.UTF_8))));
        httpPost.setEntity( build.build());
        try(CloseableHttpResponse response = httpClient.execute(httpPost)) {
            return EntityUtils.toString(response.getEntity());
        } catch (Exception e) {
            log.error("http.postFile", e);
            throw new YinXingException("http.postFile出现异常");
        }
    }

    /**
     * get请求返回字符串
     * @param url http路径 (后可跟参数?p1=aaa&p2=bbb&p3=ccc)
     * @return 响应内容字符串
     */
    public static String getString(String url) {
        HttpGet httpget = new HttpGet(url);
        try(CloseableHttpResponse response = httpClient.execute(httpget)) {
            return EntityUtils.toString(response.getEntity());
        } catch (Exception e) {
            log.error("http.getString", e);
            throw new YinXingException("http.getString出现异常");
        }
    }

    /**
     * get请求返回字符串
     * @param url http路径
     * @param param 请求参数
     * @return 响应内容字符串
     */
    public static String getString(String url, Map<String, String> param) {
        CloseableHttpResponse response = null;
        try {
            URIBuilder builder = new URIBuilder(url);
            Set<String> set = param.keySet();
            for(String key: set){
                builder.setParameter(key, param.get(key));
            }
            HttpGet httpget = new HttpGet(builder.build());
            response = httpClient.execute(httpget);
            return EntityUtils.toString(response.getEntity());
        } catch (Exception e) {
            log.error("http.getString", e);
            throw new YinXingException("http.getString出现异常");
        } finally {
            closeResource(response);
        }
    }

    /**
     * get请求
     * @param url http路径 (后可跟参数?p1=aaa&p2=bbb&p3=ccc)
     * @return 响应内容
     */
    public static byte[] getBytes(String url) {
        HttpGet httpget = new HttpGet(url);
        try(CloseableHttpResponse response = httpClient.execute(httpget)) {
            return EntityUtils.toByteArray(response.getEntity());
        } catch (Exception e) {
            log.error("http.getString", e);
            throw new YinXingException("http.getString出现异常");
        }
    }

    /**
     * get请求返回字符串
     * @param url http路径
     * @param param 请求参数
     * @return 响应内容字符串
     */
    public static byte[] getBytes(String url, Map<String, String> param) {
        CloseableHttpResponse response = null;
        try {
            URIBuilder builder = new URIBuilder(url);
            Set<String> set = param.keySet();
            for(String key: set){
                builder.setParameter(key, param.get(key));
            }
            HttpGet httpget = new HttpGet(builder.build());
            response = httpClient.execute(httpget);
            return EntityUtils.toByteArray(response.getEntity());
        } catch (Exception e) {
            log.error("http.getString", e);
            throw new YinXingException("http.getString出现异常");
        } finally {
            closeResource(response);
        }
    }

    /**
     * 关闭资源
     * @param resource 关闭资源
     */
    public static void closeResource(Closeable resource) {
        try {
            if(resource != null) {
                resource.close();
            }
        } catch (Throwable e) {
        }
    }

    /**
     * 在Spring关闭后会调用destroy方法
     */
    public static void destroy() {
        log.info("httpUtils.关闭资源");
        try {
            httpClient.close();
        } catch (IOException e) {
        }
    }
}
